package com.frxuexi.lib_base.mvi

import android.util.Log
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import androidx.paging.Pager
import androidx.paging.PagingConfig
import androidx.paging.PagingSource
import androidx.paging.cachedIn
import com.frxuexi.lib_base.entity.Res
import com.google.gson.Gson
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.channels.Channel
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.catch
import kotlinx.coroutines.flow.collect
import kotlinx.coroutines.flow.flowOn
import kotlinx.coroutines.flow.receiveAsFlow
import kotlinx.coroutines.launch
import okhttp3.MediaType
import okhttp3.MediaType.Companion.toMediaTypeOrNull
import okhttp3.MultipartBody
import okhttp3.RequestBody
import java.io.File
import kotlin.random.Random

abstract class BaseViewModel<UiIntent : IUiIntent> : ViewModel() {

    private val channel = Channel<UiIntent>()

    private var _state = MutableStateFlow<UiState>(UiState.onLoading)
    val uiState: StateFlow<UiState>
        get() = _state

    init {
        viewModelScope.launch {
            channel.receiveAsFlow().collect {
                handleIntent(it)
            }
        }
    }

    abstract fun handleIntent(it: UiIntent)

    fun sendIntent(intent: UiIntent) {
        viewModelScope.launch {
            channel.send(intent)
        }
    }

    fun <T> httpRequest(request: Flow<Res<T>>, type: RequestType = RequestType.DEFAULT) {
        viewModelScope.launch {
            request.flowOn(Dispatchers.IO)
                .catch {
                    Log.i("lr", it.message.toString())
                }.collect {
                    if (it.code == 200) {
                        if (type == RequestType.DELETE||type == RequestType.UPDATE) {
                            val num = Random.nextInt()
                            _state.value = UiState.onSuccess("${it.data}-${num}", type)
                        } else {
                            _state.value = UiState.onSuccess(it.data, type)
                        }
                    } else {
                        _state.value = UiState.onError(it.message)
                    }
                }
        }
    }

    fun <T> roomRequest(request: Flow<T>, type: RequestType = RequestType.DEFAULT) {
        viewModelScope.launch {
            request.flowOn(Dispatchers.IO)
                .catch {
                    Log.i("lr", it.message.toString())
                }.collect {
                    if (it != null) {
                        _state.value = UiState.onSuccess(it, type)
                    } else {
                        _state.value = UiState.onError("操作失败")
                    }
                }
        }
    }

    fun <T : Any> pagerRequest(pagingSource: () -> PagingSource<Int, T>) {
        val dataFlow = Pager(config = PagingConfig(pageSize = 10), pagingSourceFactory = {
            pagingSource()
        }).flow.cachedIn(viewModelScope)

        viewModelScope.launch {
            dataFlow.flowOn(Dispatchers.IO).catch {
                Log.i("lr", it.message.toString())
            }.collect {
                _state.value = UiState.onSuccess(it)
            }
        }
    }

    fun toBody(item: Any): RequestBody {
        val json = Gson().toJson(item)
        return RequestBody.create("application/json".toMediaTypeOrNull(), json)
    }

    fun toMultipartBody(name: String, path: String): MultipartBody {
        val body = RequestBody.create("multipart/form-data".toMediaTypeOrNull(), File(path))
        return MultipartBody.Builder().addFormDataPart("file", name, body).build()
    }
}